package admin

import (
	j_log "config-client-v1/init/j-log"
	"config-client-v1/model"
	"config-client-v1/utils/tools"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"gorm.io/gorm"
	"io/ioutil"
	"runtime"
	"strconv"
	"time"
)

type DebugController struct {
}

func (con DebugController) Ping(ctx *gin.Context) {
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    "pong",
	})
}

/*
	说明：本页函数全部用于测试
*/
// Test 测试用
type Boat struct {
	Photo string `json:"photo"`
	IP    string `json:"ip"`
}

func (con DebugController) Test(ctx *gin.Context) {
	param := Boat{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	jsonB, _ := json.Marshal(&param)
	_ = tools.WriteStringToLog(string(jsonB), "boat.log", "a")
	// 解码Base64字符串
	decoded, err := base64.StdEncoding.DecodeString(param.Photo)
	if err != nil {
		fmt.Println("decode error:", err)
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	err = ioutil.WriteFile(time.Now().Format("20060102150405")+".png", decoded, 0644) // output.png 是输出的图片文件名
	if err != nil {
		fmt.Println("write file error:", err)
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	fmt.Println("图片已成功保存为 output.png")
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

// Info 程序运行信息; 可用CPU数量, 协程数量
func (con DebugController) Info(ctx *gin.Context) {
	boat := Boat{}
	str, err := tools.ReadFileContent("boat.json")
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
			"data":    map[string]interface{}{},
		})
		return
	}
	err = json.Unmarshal([]byte(str), &boat)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": err.Error(),
			"data":    map[string]interface{}{},
		})
		return
	}

	cpuNum := runtime.NumCPU()
	goroutineNum := runtime.NumGoroutine()
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"CPU数量": cpuNum,
			"协程数量":  goroutineNum,
		},
	})
}

// WSClientInfo websocket 客户端连接信息
func (con DebugController) WSClientInfo(ctx *gin.Context) {
	model.WSClientMap.RLock()
	defer model.WSClientMap.RUnlock()
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"ws_client_map": model.WSClientMap.M,
		},
	})
}

// VariablesInfo  内存中变量信息, 全部和单个
func (con DebugController) VariablesInfo(ctx *gin.Context) {
	param := struct {
		Addr string `json:"addr" binding:"max=20"`
	}{}
	if ctx.Request.Method == "POST" {
		err := ctx.ShouldBindBodyWith(&param, binding.JSON)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数",
				"data":    err.Error(),
			})
			return
		}
	} else {
		param.Addr = ctx.Query("addr")
	}
	addr := param.Addr
	if addr != "" {
		v, ok := model.VariablesMap.Get(addr)
		if !ok {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "未找到当前变量",
			})
			return
		}
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data": map[string]interface{}{
				"v": v,
			},
		})
		return
	}
	model.VariablesMap.RLock()
	defer model.VariablesMap.RUnlock()
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"variables_map": model.VariablesMap.M,
		},
	})
}

// AlertDataMapInfo  查看内存中最近一次报警变量信息
func (con DebugController) AlertDataMapInfo(ctx *gin.Context) {
	param := struct {
		Addr string `json:"addr" binding:"max=20"`
	}{}
	if ctx.Request.Method == "POST" {
		err := ctx.ShouldBindBodyWith(&param, binding.JSON)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数",
				"data":    err.Error(),
			})
			return
		}
	} else {
		param.Addr = ctx.Query("addr")
	}
	addr := param.Addr
	if addr != "" {
		v, ok := model.AlertDataMap.Get(addr)
		if !ok {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "未找到当前变量",
			})
			return
		}
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data": map[string]interface{}{
				"v": v,
			},
		})
		return
	}
	model.AlertDataMap.RLock()
	defer model.AlertDataMap.RUnlock()
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"variables_map": model.AlertDataMap.M,
		},
	})
}

func (con DebugController) MemValueUpdate(ctx *gin.Context) {
	projectIDQuery := ctx.Query("project_id")
	addrQuery := ctx.Query("addr")
	valueQuery := ctx.Query("value")
	projectID, _ := strconv.Atoi(projectIDQuery)
	if projectID == 0 {
		projectID = 1
	}
	valueFloat, _ := strconv.ParseFloat(valueQuery, 64)
	if addrQuery == "" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请传入参数 addr",
			"data":    "",
		})
		return
	}

	info := &model.Variable{}
	err := model.DB.Model(&model.Variable{}).Where("project_id = ? AND addr = ?", projectID, addrQuery).First(&info).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	if info.SpecType != "string" {
		updateData := map[string]interface{}{
			"value": valueFloat,
		}
		err = model.DB.Model(&model.Variable{}).Where("id = ?", info.ID).Updates(updateData).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
	}

	exist, ok := model.VariablesMap.Get(info.Addr)
	if ok {
		if info.SpecType != "string" {
			exist.Value = valueFloat
		} else {
			exist.ValueStr = valueQuery
		}
	} else {
		if info.SpecType != "string" {
			info.Value = valueFloat
		} else {
			info.ValueStr = valueQuery
		}
		model.VariablesMap.Set(info.Addr, info)
	}

	err = model.WriteVariablesToModbusPoint(info.Addr, valueFloat)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "写入Modbus点位值失败",
			"data":    err.Error(),
		})
		return
	}
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}

// VariablesInit 初始化工程变量(废弃)
func (con DebugController) VariablesInit(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	project := model.Project{}
	err := model.DB.Preload("PPEList", func(tx *gorm.DB) *gorm.DB {
		return tx.Preload("FrameList", func(tx2 *gorm.DB) *gorm.DB {
			return tx2.Preload("FrameItem").Where("del = 0")
		}).Where("del = 0")
	}).Preload("FSEList", func(tx *gorm.DB) *gorm.DB {
		return tx.Preload("FSModule", func(tx2 *gorm.DB) *gorm.DB {
			return tx2.Preload("FrameItem").Where("del = 0")
		}).Where("del = 0")
	}).Where("id = ? AND del = 0", userToken.ProjectID).Limit(1).First(&project).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": "无效的project_id",
			"data":    err,
		})
		return
	}
	// 初始化fse变量到内存中
	for _, fse := range project.FSEList {
		err = fse.UpdateVariablesMap()
		if err != nil {
			j_log.LogError([]interface{}{"初始化fse变量失败: ", err.Error()})
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "初始化fse变量失败",
				"data":    err,
			})
			return
		}
	}
	// 初始化ppe变量到内存中
	for _, ppe := range project.PPEList {
		err = ppe.UpdateVariablesMap()
		if err != nil {
			j_log.LogError([]interface{}{"初始化ppe变量失败: ", err.Error()})
			ctx.JSON(200, gin.H{
				"code":    1,
				"message": "初始化ppe变量失败",
				"data":    err,
			})
			return
		}
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})

}

// TempFSE 查看上载的临时数据
func (con DebugController) TempFSE(ctx *gin.Context) {
	fseIDStr := ctx.Query("fse_id")
	fseID, _ := strconv.Atoi(fseIDStr)
	if fseID == 0 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "fse_id 不能为空",
			"data":    map[string]interface{}{},
		})
		return
	}
	fse, ok := model.TempFSMap.Get(fseID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "未找到 fse_id 上载的临时数据",
			"data":    map[string]interface{}{},
		})
		return
	}
	filePath := "temp_fse.json"
	jsonB, _ := json.MarshalIndent(fse, "", "  ")
	_ = tools.WriteStringToFile(string(jsonB), filePath, "w")
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"output_path": filePath,
		},
	})
}

func (con DebugController) RunningFSE(ctx *gin.Context) {
	fseIDStr := ctx.Query("fse_id")
	fseID, _ := strconv.Atoi(fseIDStr)
	if fseID == 0 {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "fse_id不能为空",
			"data":    map[string]interface{}{},
		})
		return
	}
	fse, ok := model.RunningFSMap.Get(fseID)
	if !ok {
		ctx.JSON(200, gin.H{
			"code":    1,
			"message": "未找到fse运行数据",
			"data":    map[string]interface{}{},
		})
		return
	}
	filePath := "running_fse.json"
	jsonB, _ := json.MarshalIndent(fse, "", "  ")
	_ = tools.WriteStringToFile(string(jsonB), filePath, "w")
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"output_path": filePath,
		},
	})
}

func (con DebugController) ExpAlarmItemsInfo(ctx *gin.Context) {
	model.ExpAlarmItems.Lock()
	defer model.ExpAlarmItems.Unlock()
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list": model.ExpAlarmItems.Data,
		},
	})
}

// StdLogInfo 控制台日志输出
func (con DebugController) StdLogInfo(ctx *gin.Context) {
	list := j_log.GetLogList(10)
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"std_out": list,
		},
	})
}

func (con DebugController) ResetCache(ctx *gin.Context) {
	model.ImportingProjectExt = nil
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}
